Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Commit 9dee9b0662468e4db22d49ace1ffea22006be1c5


Parents : d8a3076
Author : Sudo-Ivan <ivan@quad4.io>
Signature : Signature validation error
Date : 2026-03-06T01:02:36-06:00

Add identity export functionality with ZIP compression

- Implemented a new API endpoint to export all identities as a ZIP file.
- Added a method in IdentityManager to retrieve all identity backup bytes for export.
- Enhanced error handling for the export process to provide user feedback in case of failures.

Changes

2 files changed, 50 insertions(+), 0 deletions(-)


Diff

diff --git a/meshchatx/meshchat.py b/meshchatx/meshchat.py
index d354f24f..78643fb3 100644
--- a/meshchatx/meshchat.py
+++ b/meshchatx/meshchat.py
@@ -24,6 +24,8 @@ import threading
import time
import traceback
import webbrowser
+import io
+import zipfile
import fnmatch
from datetime import UTC, datetime, timedelta
from logging.handlers import RotatingFileHandler
@@ -4414,6 +4416,35 @@ class ReticulumMeshChat:
status=500,
)
+ @routes.get("/api/v1/identities/export-all")
+ async def identities_export_all(request):
+ try:
+ all_bytes = self.identity_manager.get_all_identity_backup_bytes()
+ if not all_bytes:
+ return web.json_response(
+ {"message": "No identities to export"},
+ status=400,
+ )
+ buf = io.BytesIO()
+ with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as zf:
+ for identity_hash, data in all_bytes.items():
+ zf.writestr(f"identity_{identity_hash}", data)
+ buf.seek(0)
+ return web.Response(
+ body=buf.read(),
+ headers={
+ "Content-Type": "application/zip",
+ "Content-Disposition": 'attachment; filename="identities_export.zip"',
+ },
+ )
+ except Exception as e:
+ return web.json_response(
+ {
+ "message": f"Failed to export identities: {e!s}",
+ },
+ status=500,
+ )
+
@routes.post("/api/v1/identities/create")
async def identities_create(request):
try:

diff --git a/meshchatx/src/backend/identity_manager.py b/meshchatx/src/backend/identity_manager.py
index 2dc4add9..bb0213e0 100644
--- a/meshchatx/src/backend/identity_manager.py
+++ b/meshchatx/src/backend/identity_manager.py
@@ -36,6 +36,25 @@ class IdentityManager:
def backup_identity_base32(self, identity: RNS.Identity) -> str:
return base64.b32encode(self.get_identity_bytes(identity)).decode("utf-8")
+ def get_all_identity_backup_bytes(self) -> dict[str, bytes]:
+ result = {}
+ identities_base_dir = os.path.join(self.storage_dir, "identities")
+ if not os.path.exists(identities_base_dir):
+ return result
+ for identity_hash in os.listdir(identities_base_dir):
+ identity_path = os.path.join(identities_base_dir, identity_hash)
+ if not os.path.isdir(identity_path):
+ continue
+ identity_file = os.path.join(identity_path, "identity")
+ if not os.path.isfile(identity_file):
+ continue
+ try:
+ with open(identity_file, "rb") as f:
+ result[identity_hash] = f.read()
+ except Exception:
+ continue
+ return result
+
def list_identities(self, current_identity_hash: str | None = None):
identities = []
identities_base_dir = os.path.join(self.storage_dir, "identities")


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────